package data

import (
	"database/sql"
	"errors"
	"fmt"
	"gitchina/kly_service/util"
	"github.com/astaxie/beego/orm"
	_ "github.com/go-sql-driver/mysql"
	"strconv"
)

type WaybillDto struct {
	Id             int     `orm:"pk;auto;column(id)"`
	CargoOwnerId   int     `orm:"column(cargo_owner_id)"`
	CarrierOwnerId int     `orm:"column(carrier_owner_id)"`
	CarrierPubId   int     `orm:"column(carrier_pub_id)"`
	ShipmentTime   string  `orm:"column(shipment_time)"`
	StartArea      int     `orm:"column(start_area)"`
	StartAddr      string  `orm:"column(start_addr)"`
	EndArea        int     `orm:"column(end_area)"`
	EndAddr        string  `orm:"column(end_addr)"`
	CargoName      string  `orm:"column(cargo_name)"`
	CargoType      int     `orm:"column(cargo_type)"`
	CargoBulk      int     `orm:"column(cargo_bulk)"`
	CargoWeight    int     `orm:"column(cargo_weight)"`
	CargoCount     int     `orm:"column(cargo_count)"`
	CargoValue     float32 `orm:"column(cargo_value)"`
	ArrivalTime    string  `orm:"column(arrival_time)"`
	Deposit        float32 `orm:"column(deposit)"`
	Price          float32 `orm:"column(price)"`
	Consignor      string  `orm:"column(consignor)"`
	Consignee      string  `orm:"column(consignee)"`
	ConsigneePhone string  `orm:"column(consignee_phone)"`
	State          int     `orm:"column(state)"`
	Remark         string  `orm:"column(remark)"`
}

type GetWaybillListDto struct {
	Id           int     `orm:"column(id)"`
	ShipmentTime string  `orm:"column(shipment_time)"`
	StartArea    int     `orm:"column(start_area)"`
	EndArea      int     `orm:"column(end_area)"`
	Deposit      float32 `orm:"column(deposit)"`
	Price        float32 `orm:"column(price)"`
	CargoType    int     `orm:"column(cargo_type)"`
	CargoName    string  `orm:"column(cargo_name)"`
	State        int     `orm:"column(state)"`
}

type WaybillDetailDto struct {
	CargoOwner        string  `orm:"column(cargo_owner)"`
	CarrierOwner      string  `orm:"column(carrier_owner)"`
	StartArea         int     `orm:"column(start_area)"`
	StartAddr         string  `orm:"column(start_addr)"`
	EndArea           int     `orm:"column(end_area)"`
	EndAddr           string  `orm:"column(end_addr)"`
	VehicleNo         string  `orm:"column(vehicle_no)"`
	VehicleType       int     `orm:"column(vehicle_type)"`
	VehicleLen        int     `orm:"column(vehicle_len)"`
	VehicleLoad       int     `orm:"column(vehicle_load)"`
	ShipmentTime      string  `orm:"column(shipment_time)"`
	ArrivalTime       string  `orm:"column(arrival_time)"`
	CarrierPubId      int     `orm:"column(carrier_pub_id)"`
	CargoName         string  `orm:"column(cargo_name)"`
	CargoType         int     `orm:"column(cargo_type)"`
	CargoBulk         int     `orm:"column(cargo_bulk)"`
	CargoWeight       int     `orm:"column(cargo_weight)"`
	CargoCount        int     `orm:"column(cargo_count)"`
	CargoValue        float32 `orm:"column(cargo_value)"`
	Deposit           float32 `orm:"column(deposit)"`
	Price             float32 `orm:"column(price)"`
	Consignor         string  `orm:"column(consignor)"`
	Consignee         string  `orm:"column(consignee)"`
	ConsigneePhone    string  `orm:"column(consignee_phone)"`
	Remark            string  `orm:"column(remark)"`
	CarrierOwnerId    int     `orm:"column(carrier_owner_id)"`
	CargoOwnerId      int     `orm:"column(cargo_owner_id)"`
	State             int     `orm:"column(state)"`
	NeedInvoice       bool    `orm:"column(need_invoice)"`
	PaymentTerm       int     `orm:column(payment_term)`
	CarrierOwnerPhone string  `orm:"column(carrier_owner_phone)"`
	CargoOwnerPhone   string
}

type LetterOfAuthorizationDto struct {
	CarrierOwner string `orm:"column(carrier_owner)"`
	IDCardNo     string `orm:"column(id_card_no)"`
	VehicleNo    string `orm:"column(vehicle_no)"`
}

type WaybillOwnerDto struct {
	CargoOwnerId   int    `orm:"column(cargo_owner_id)"`
	CarrierOwnerId int    `orm:"column(carrier_owner_id)"`
	Consignor      string `orm:"column(consignor)"`
	ArrivalTime    string `orm:"column(arrival_time)"`
	StartAddr      string `orm:"column(start_addr)"`
	EndAddr        string `orm:"column(end_addr)"`
	Consignee      string `orm:"column(consignee)"`
	ConsigneePhone string `orm:"column(consignee_phone)"`
}

func init() {
	orm.RegisterModel(new(WaybillDto))
}

func (dto *WaybillDto) TableName() string {
	return "o_waybill"
}

func (repo OrderRepo) MakeWaybill(dto *WaybillDto) (id int64, err error) {
	var num int64
	var list orm.ParamsList
	o := orm.NewOrm()
	err = o.Begin()
	if err == nil {
		num, err = o.Raw(SQL_Order_Ensure_Only_One_Waybill, dto.CargoOwnerId, dto.CarrierPubId).ValuesFlat(&list)
		if num >= 1 {
			o.Rollback()
		} else {
			id, err = o.Insert(dto)
			if err != nil {
				o.Rollback()
			} else {
				_, err = o.Raw(SQL_Order_Freeze_Carrier_Pub, dto.CarrierPubId).Exec()
				if err != nil {
					o.Rollback()
				} else {
					o.Commit()
				}
			}
		}
	}
	return
}

func (repo OrderRepo) GetWaybillList(id, pageNo, pageSize int, queryState, mbrType string) ([]GetWaybillListDto, int, error) {
	var sql string
	var rowCountSql string
	var num int64
	var rowCount int
	var err error
	var flat orm.ParamsList
	var waybillList []GetWaybillListDto
	o := orm.NewOrm()

	var stateWhere string
	if queryState == "1" {
		stateWhere = " AND state < 7"
	} else if queryState == "2" {
		stateWhere = " AND state >= 7"
	}

	if mbrType == "1" || mbrType == "3" {
		sql = fmt.Sprintf(SQL_Order_Get_Waybill_By_Cargo_Owner, stateWhere, (pageNo-1)*pageSize, pageSize)
		rowCountSql = fmt.Sprintf(SQL_Order_Get_Waybill_By_Cargo_Owner_Count, stateWhere)
	} else if mbrType == "2" {
		sql = fmt.Sprintf(SQL_Order_Get_Waybill_By_Carrier_Owner, stateWhere, (pageNo-1)*pageSize, pageSize)
		rowCountSql = fmt.Sprintf(SQL_Order_Get_Waybill_By_Carrier_Owner_Count, stateWhere)
	} else {
		return nil, 0, errors.New("invalid member type")
	}
	if num, err = o.Raw(sql, id).QueryRows(&waybillList); num >= 1 {
		if num, err = o.Raw(rowCountSql, id).ValuesFlat(&flat); num >= 1 {
			rowCount, err = strconv.Atoi(flat[0].(string))
			util.GetLogger().Debug("[data-GetWaybillList] - debug:rowcount::%s", flat[0])
		}
	}
	return waybillList, rowCount, err
}

func (repo OrderRepo) GetWaybillDetail(id int) (dto WaybillDetailDto, err error) {
	var mbrType string
	var cargoOwner CargoOwnerGetDto
	var logiCorp LogisticsCorpDetailDto
	o := orm.NewOrm()
	if err = o.Raw(SQL_Order_Get_Waybill_Detail, id).QueryRow(&dto); err == nil {
		var mbrRepo MemberRepo
		if mbrType, err = mbrRepo.GetMemberType(dto.CargoOwnerId); err == nil {
			if mbrType == "1" {
				if cargoOwner, err = mbrRepo.GetCargoOwner(dto.CargoOwnerId); err == nil {
					if cargoOwner.IsCorp {
						dto.CargoOwner = cargoOwner.CorpName
					} else {
						dto.CargoOwner = cargoOwner.Name
					}
					dto.CargoOwnerPhone = cargoOwner.Phone
				}
			} else if mbrType == "3" {
				var logiRepo LogisticsRepo
				if logiCorp, err = logiRepo.GetLogisticsCorpDetail(dto.CargoOwnerId); err == nil {
					dto.CargoOwner = logiCorp.CorpName
					dto.CargoOwnerPhone = logiCorp.OwnerPhone
				}
			}
		}
	}
	return dto, err
}

func (repo OrderRepo) GetWaybillState(waybillId int) (state int, updTime string, err error) {
	var num int64
	var list orm.ParamsList
	state = -1
	o := orm.NewOrm()
	if num, err = o.Raw(SQL_Order_Get_Waybill_State, waybillId).ValuesFlat(&list); num > 0 {
		state, err = strconv.Atoi(list[0].(string))
		updTime = list[1].(string)
	}
	return
}

func (repo OrderRepo) UpdateWaybill(dto *WaybillDto) error {
	o := orm.NewOrm()
	_, err := o.Raw(SQL_Order_Update_Waybill, dto.ShipmentTime, dto.StartArea, dto.StartAddr,
		dto.EndArea, dto.EndAddr, dto.CargoName, dto.CargoType, dto.CargoBulk, dto.CargoWeight, dto.Deposit, dto.Price, dto.Consignor, dto.Remark, dto.CargoCount, dto.CargoValue, dto.Consignee, dto.ConsigneePhone, dto.ArrivalTime, dto.Id, dto.CargoOwnerId).Exec()

	return err
}

func (repo OrderRepo) UpdateWaybillState(waybillId, mbrId, state int, parmas ...interface{}) (err error) {
	var sql string
	o := orm.NewOrm()
	switch state {
	case 2:
		sql = SQL_Order_Switch_OnTheWay
	case 5:
		sql = SQL_Order_Switch_OnShipment
	case 6:
		sql = SQL_Order_Switch_OnArrival
	}
	if sql != "" {
		_, err = o.Raw(sql, waybillId, mbrId, parmas).Exec()
	} else {
		err = errors.New("invalid order state")
	}

	return err
}

func (repo OrderRepo) UpdateWaybillStateWithParams(waybillId, mbrId, invoiceCorpId, paymentTerm int, needInvoice, needInsurance bool, price float32, invoiceDto *InvoiceDto) (err error) {
	o := orm.NewOrm()
	if needInvoice {
		if err = o.Begin(); err == nil {
			invoiceDto.CorpId = invoiceCorpId
			invoiceDto.Amount = price
			invoiceDto.WaybillId = waybillId
			invoiceDto.State = 0
			invoiceDto.MemberId = mbrId

			if _, err = o.Insert(invoiceDto); err == nil {
				if _, err = o.Raw(SQL_Order_Switch_OnContract_Wait2Confirm, needInvoice, needInsurance, paymentTerm, waybillId, mbrId).Exec(); err == nil {
					o.Commit()
				} else {
					o.Rollback()
				}
			} else {
				o.Rollback()
			}
		} else {
			o.Rollback()
		}
	} else {
		_, err = o.Raw(SQL_Order_Switch_OnContract_Wait2Confirm, needInvoice, needInvoice, paymentTerm, waybillId, mbrId).Exec()
	}

	return err
}

func (repo OrderRepo) CompleteWaybill(waybillId, cargoOwnerId int) (err error) {
	var num int64
	var list orm.ParamsList
	var result sql.Result
	var rowsAffected int64
	o := orm.NewOrm()
	if num, err = o.Raw(SQL_Order_Get_Pub_Id_By_Waybill_Id, waybillId).ValuesFlat(&list); num >= 1 {
		if err = o.Begin(); err == nil {
			if result, err = o.Raw(SQL_Order_Switch_Complete, waybillId, cargoOwnerId).Exec(); err == nil {
				if rowsAffected, err = result.RowsAffected(); rowsAffected >= 1 {
					if _, err = o.Raw(fmt.Sprintf(SQL_Order_Set_Carrier_Pub, 2), list[0].(string)).Exec(); err == nil {
						o.Commit()
					} else {
						o.Rollback()
					}
				} else {
					o.Rollback()
				}
			} else {
				o.Rollback()
			}
		} else {
			o.Rollback()
		}
	}
	return
}

func (repo OrderRepo) CancelWaybill(waybillId, mbrId int) (err error) {
	var num int64
	var list orm.ParamsList
	var result sql.Result
	var rowsAffected int64
	o := orm.NewOrm()
	if num, err = o.Raw(SQL_Order_Get_Pub_Id_By_Waybill_Id, waybillId).ValuesFlat(&list); num >= 1 {
		if err = o.Begin(); err == nil {
			if result, err = o.Raw(SQL_Order_Switch_Cancel, waybillId, mbrId, mbrId).Exec(); err == nil {
				if rowsAffected, err = result.RowsAffected(); rowsAffected >= 1 {
					if _, err = o.Raw(fmt.Sprintf(SQL_Order_Set_Carrier_Pub, 0), list[0].(string)).Exec(); err == nil {
						o.Commit()
					} else {
						o.Rollback()
					}
				} else {
					o.Rollback()
				}
			} else {
				o.Rollback()
			}
		} else {
			o.Rollback()
		}
	}

	return err
}

func (repo OrderRepo) GetWaybillOwners(waybillId int) (dto WaybillOwnerDto, err error) {
	o := orm.NewOrm()
	err = o.Raw(SQL_Order_Get_Waybill_Owner, waybillId).QueryRow(&dto)
	return
}

func (repo OrderRepo) GetLetterOfAuthorization(memberId, waybillId int) (dto LetterOfAuthorizationDto, err error) {
	o := orm.NewOrm()
	err = o.Raw(SQL_Order_Get_Letter_Of_Authorization, waybillId, memberId).QueryRow(&dto)
	return
}
